<!--
 * @Author: Charsen
 * @Date: 2025-07-23 14:36
 * @LastEditors: wjc
 * @LastEditTime: 2025-10-30 17:08:36
 * @Description: 
-->
<template>
  <Content>
    <el-row class="body-container">
      <el-col :span="leftSpan">
        <slot name="left"></slot>
      </el-col>
      <el-col :span="rightSpan" :style="tableStyle">
        <div v-loading="listLoading" class="p-20px wh-full flex flex-col">
          <div class="h-32px">
            <OptionTrashed
              v-if="showTrashed"
              v-action="actions.trashed"
              :entity="entity"
              :trashed-route="getTrashedRoute()"
              class="mt-6px ml-20px"
              :right="true"
              :show-text="true"
            />
            <el-button plain @click="horizontalChange">
              {{ treeHorizontal ? '竖向' : '横向' }}
            </el-button>
            <el-button plain @click="expandChange">
              {{ expandAll ? '全收起' : '全展开' }}
            </el-button>
          </div>
          <div class="wh-full flex-1 overflow-x-auto text-center">
            <!-- <OrgTree
              class="my-60px mx-auto"
              :data="list"
              :horizontal="treeHorizontal"
              :collapsable="treeCollapsable"
              :render-content="renderContent"
              @on-expand="onExpand"
            /> -->
            <Vue3TreeOrg
              :data="list"
              :props="{
                id: 'value',
                pid: 'pid',
                label: 'label',
                children: 'children',
                expand: 'expand',
              }"
              center
              :label-style="{
                background: 'hsl(var(--card-accent))',
                color: 'hsl(var(--text-primary))',
              }"
              :render-content="renderContent"
              :horizontal="treeHorizontal"
              :collapsable="treeCollapsable"
              @on-expand="onExpand"
            />
          </div>
        </div>
      </el-col>
    </el-row>

    <Creator
      v-model:visible="createDialog.visible"
      :entity="entity"
      :request-url="createUrl"
      @on-stored="loadData"
    />

    <Editor
      v-model:visible="editDialog.visible"
      :entity-id="editDialog.id"
      :entity="entity"
      @on-updated="loadData"
    />
  </Content>
</template>

<script setup lang="tsx">
  import { api, Http } from '#/api'
  import { useCreator } from '#/hooks/useCreator'
  import { useDestroy } from '#/hooks/useDestroy'
  import { useEditor } from '#/hooks/useEditor'
  import { useLister } from '#/hooks/useLister'
  import checkAction from '#/utils/check-action'
  import { useVModel } from '@vueuse/core'
  import { Vue3TreeOrg } from 'vue3-tree-org'

  import 'vue3-tree-org/lib/vue3-tree-org.css'

  defineOptions({
    name: 'ScaffoldTreeShape',
  })

  const props = withDefaults(
    defineProps<{
      actions: object
      entity: string
      expand?: boolean
      horizontal?: boolean
      leftSpan?: number
      requestUrl?: RequestUrl
      showTrashed?: boolean
    }>(),
    {
      actions: () => ({}),
      leftSpan: 0,
      showTrashed: false,
      horizontal: false,
      expand: false,
      requestUrl: () => ({}),
    }
  )

  const emits = defineEmits(['update:horizontal', 'update:expand'])

  const treeCollapsable = ref(true)
  const treeHorizontal = useVModel(props, 'horizontal', emits)
  const expandAll = useVModel(props, 'expand', emits)

  // 使用 useLister hook
  const { list, listLoading, fetchData, fetchDataWith, searchFormer, getTrashedRoute } = useLister({
    entity: props.entity,
  })

  // 使用 useCreator hook
  const { createDialog, showCreator } = useCreator({ entity: props.entity })

  // 使用 useEditor hook
  const { editDialog, showEditor } = useEditor({ entity: props.entity })

  // 使用 useDestroy hook
  const { handleDestroy } = useDestroy({ entity: props.entity })

  const rightSpan = computed(() => 24 - props.leftSpan)
  const tableStyle = computed(() => (props.leftSpan > 0 ? 'border-left: 1px solid #EBEEF5' : ''))

  const createUrl = ref<RequestUrl>({ create: api[props.entity].create })
  const getCreateForm = (id: string) => {
    createUrl.value.params = { id }
    showCreator()
  }

  const handleDelete = (id: number | string): void => {
    handleDestroy(id, () => loadData())
  }

  const renderContent = (h: any, data: any) => {
    return h(
      <el-dropdown
        class="org-tree-dropdown"
        placement="bottom"
        trigger="click"
        v-slots={{
          dropdown: () => (
            <el-dropdown-menu>
              {data.id > 0 && checkAction(props.actions.edit) ? (
                <el-dropdown-item onClick={showEditor.bind(this, data.id)}>
                  <i class="i-custom-edit font-s-12px color-info"></i>
                  编辑
                </el-dropdown-item>
              ) : (
                ''
              )}
              {data.id > 0 && checkAction(props.actions.del) ? (
                <el-dropdown-item onClick={handleDelete.bind(this, data.id)}>
                  <i class="i-custom-delete font-s-12px color-info"></i>
                  删除
                </el-dropdown-item>
              ) : (
                ''
              )}
              {data.id > 0 && checkAction(props.actions.edit) ? (
                <el-dropdown-item divided onClick={handelMove.bind(this, data.id, 'front')}>
                  <i class="i-custom-move-front font-s-12px color-info"></i>
                  往前移
                </el-dropdown-item>
              ) : (
                ''
              )}
              {data.id > 0 && checkAction(props.actions.edit) ? (
                <el-dropdown-item onClick={handelMove.bind(this, data.id, 'back')}>
                  <i class="i-custom-move-front font-s-12px color-info"></i>
                  往后移
                </el-dropdown-item>
              ) : (
                ''
              )}
              {checkAction(props.actions.add) ? (
                <el-dropdown-item divided={data.id > 0} onClick={getCreateForm.bind(this, data.id)}>
                  <i class="i-custom-add font-s-12px color-info"></i>
                  新增下级
                </el-dropdown-item>
              ) : (
                ''
              )}
            </el-dropdown-menu>
          ),
        }}
      >
        <div class="flex-center min-w-100px whitespace-nowrap break-keep p-4">
          <span>{data.label}</span>
          <i class="i-ep-more-filled ml-20px color-info cursor-pointer"></i>
        </div>
      </el-dropdown>
    )
  }

  /**
   * 树展开伸缩
   */
  const toggleExpand = (data: any, val: boolean) => {
    if (Array.isArray(data)) {
      data.forEach((item) => {
        item.expand = val
        if (item.children) {
          toggleExpand(item.children, val)
        }
      })
    } else {
      data.expand = val
      if (data.children) {
        toggleExpand(data.children, val)
      }
    }
  }

  const expandChange = () => {
    toggleExpand(list.value, !expandAll.value)
    // 因为用了 v-model，所以值的变化需要 emit('update:') 后再回来有滞后，所以先执行，再改值
    expandAll.value = !expandAll.value
  }

  const horizontalChange = () => {
    treeHorizontal.value = !treeHorizontal.value
  }

  const collapse = (list: any[]) => {
    list.forEach((child) => {
      if (child.expand) {
        child.expand = false
      }
      child.children && collapse(child.children)
    })
  }

  /**
   * 展开伸缩下级
   */
  const onExpand = (data: any) => {
    if ('expand' in data) {
      data.expand = !data.expand
      if (!data.expand && data.children) {
        collapse(data.children)
      }
    } else {
      list.value = {
        ...list.value,
        expand: true,
      }
    }
  }

  const handelMove = (id: number | string, direction: string) => {
    listLoading.value = true
    searchFormer.data.move_direction = direction

    Http.Post(api[props.entity].move(id), searchFormer)
      .then(() => {
        loadData()
      })
      .finally(() => {
        listLoading.value = false
      })
  }

  const loadData = () => {
    const onFetched = () => {
      if (expandAll.value) toggleExpand(list.value, expandAll.value)
    }
    props.requestUrl.index
      ? fetchDataWith({ index: props.requestUrl.index, params: props.requestUrl.params }, onFetched)
      : fetchData(onFetched)
  }

  defineExpose({
    searchFormer,
    fetchData: loadData,
  })

  onMounted(() => {
    loadData()
  })
</script>

<style scoped lang="scss">
  .body-container {
    height: calc(100vh - 118px);
    border-radius: 6px;
    box-shadow: 0 0 5px rgb(0 0 0 / 10%);

    :deep(.zm-tree-org) {
      @apply bg-card;
    }
  }
</style>
